package org.jeecg.modules.charge.service.impl;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Base64.Decoder;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.impl.compression.CompressionCodecs;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.jeecg.common.util.StringUtils;
import org.jeecg.modules.charge.entity.BwInvoiceEntity.BlueInvoice;
import org.jeecg.modules.charge.entity.BwInvoiceEntity.BlueInvoiceDetailed;
import org.jeecg.modules.charge.entity.YyInvoiceEntity.JwtParamBuilder;
import org.springframework.stereotype.Service;
import com.google.gson.GsonBuilder;
/**
 *开具蓝票接口测试
  @author: Litao
  @date：      日期：2018年9月10日 
  @time:   时间：下午5:13:11
 */

@Service
public class BlueInvoiceService {
	static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger( BlueInvoiceService.class);

/**
 * 请求开票
 * @param bin
 * @return
 * @throws Exception
 */
public String callInvoiceApply(BlueInvoice bin) throws Exception {
    String url = bin.getUrl();
    log.info("开票URL:"+url);
    HttpClient httpClient = HttpClients.custom().build();
    HttpPost httpPost = new HttpPost(url);
    // 构造POST表单Map
    Map<String, String> paramsMap = buildPostParam(bin);
    // 签名
    String sign = this.sign(paramsMap,bin);
    httpPost.addHeader("sign", sign);
    // 转换POST表单参数
    List<BasicNameValuePair> list = new ArrayList<BasicNameValuePair>();
    Iterator<Entry<String, String>> iterator = paramsMap.entrySet().iterator();
    while (iterator.hasNext()) {
	Entry<String, String> elem =iterator.next();
      list.add(new BasicNameValuePair(elem.getKey(), elem.getValue()));
    }
    log.info(list.toString());
    if (list.size() > 0) {
      UrlEncodedFormEntity entity = new UrlEncodedFormEntity(list, "UTF-8");
      httpPost.setEntity(entity);
    }
    // 发送http post请求，并得到响应结果
    HttpResponse response = httpClient.execute(httpPost);
    String result = "";
    if (response != null) {
      HttpEntity resEntity = response.getEntity();
      if (resEntity != null) {
        result = EntityUtils.toString(resEntity, "UTF-8");
        log.info(result);
      }
    }
    return result;
  }

public static byte[] getStringImage(String base64String) throws IOException {
	Decoder decoder = Base64.getDecoder(); 
    return base64String != null ? decoder.decode(base64String) : null;
}


/**
 * 根据发票流水号查询发票状态
 */
public String getInvoiceData(BlueInvoice bin) throws Exception {
	if(null==bin.getFpqqlsh() || StringUtils.isEmpty(bin.getFpqqlsh())) {
		return null;
	}
	String url="https://fapiao.yonyoucloud.com/invoiceclient-web/api/invoiceApply/queryInvoiceStatus?appid="+bin.getAppid();
	/*String url = "https://www.yesfp.com/invoiceclient-web/api/invoiceApply/queryInvoiceStatus?appid="+bin.getAppid();*/
    HttpClient httpClient = HttpClients.custom().build();
    HttpPost httpPost = new HttpPost(url);
    // 构造POST表单Map
    Map<String, String> paramsMap = buildPostParam(bin);
    // 签名
    String sign = this.sign(paramsMap,bin);
    httpPost.addHeader("sign", sign);
    List<BasicNameValuePair> list = new ArrayList<BasicNameValuePair>();
    list.add(new BasicNameValuePair("fpqqlsh", bin.getFpqqlsh()));
    UrlEncodedFormEntity entity = new UrlEncodedFormEntity(list, "UTF-8");
    log.info(list.toString());
     httpPost.setEntity(entity);
    // 发送http post请求，并得到响应结果
    HttpResponse response = httpClient.execute(httpPost);
    String result = "";
    if (response != null) {
      HttpEntity resEntity = response.getEntity();
      if (resEntity != null) {
        result = EntityUtils.toString(resEntity, "UTF-8");
      }
    }
    return result;
  }


  /**
   * 获取发票请求流水号
   * 
   * @return 发票请求流水号
   */
  private String buildFpqqlsh(BlueInvoice bin) {
    return bin.getFpqqlsh();
  }


  /**
   * 签名
   * 
   * @param paramsMap 表单参数
   * @return 签名值
   * @throws Exception
   */
  private String sign(Map<String, String> paramsMap,BlueInvoice bin) throws Exception {
    // 读取CA证书与PEM格式证书需要根据实际证书使用情况而定,目前这两种都支持
    PrivateKey privateKey = loadPrivateKeyOfCA(bin);
    Map<String, Object> claims =JwtParamBuilder.build().setSubject("tester").setIssuer("einvoice").setAudience("einvoice").addJwtId().addIssuedAt().setExpirySeconds(300).setNotBeforeSeconds(300).getClaims();
    // 需要将表单参数requestdatas的数据进行md5加密，然后放到签名数据的requestdatas中。
    // 此签名数据必须存在，否则在验证签名时会不通过。
    String value = paramsMap.get("requestdatas");
    claims.put("requestdatas", getMD5(value));
    // 使用jdk1.6版本时，删除下面代码的中.compressWith(CompressionCodecs.DEFLATE)
    String compactJws = Jwts.builder().signWith(SignatureAlgorithm.RS512, privateKey).setClaims(claims).compressWith(CompressionCodecs.DEFLATE).compact();
    return compactJws;
  }


  /**
   * 计算MD5
   * 
   * @param str
   * @return
   * @throws UnsupportedEncodingException
   * @throws NoSuchAlgorithmException
   */
  private String getMD5(String str) throws UnsupportedEncodingException, NoSuchAlgorithmException {
    byte[] buf = null;
    buf = str.getBytes("utf-8");
    MessageDigest md5 = null;
    md5 = MessageDigest.getInstance("MD5");
    md5.update(buf);
    byte[] tmp = md5.digest();
    StringBuilder sb = new StringBuilder();
    for (byte b : tmp) {
      sb.append(String.format("%02x", b & 0xff));
    }
    return sb.toString();
  }



  /**
   * 读取证书私钥
   * 
   * @return
   * @throws UnrecoverableKeyException
   * @throws KeyStoreException
   * @throws NoSuchAlgorithmException
   * @throws CertificateException
   * @throws IOException
   */
  protected PrivateKey loadPrivateKeyOfCA(BlueInvoice bin) throws UnrecoverableKeyException, KeyStoreException,NoSuchAlgorithmException, CertificateException, IOException {
    String keypath =bin.getCert_url();
    log.info(keypath);
    FileInputStream in = new FileInputStream(keypath);
    KeyStore ks = KeyStore.getInstance("pkcs12");
    String pwd =bin.getPassword();
    ks.load(in, pwd.toCharArray());
    String alias = ks.aliases().nextElement();
    PrivateKey caprk = (PrivateKey) ks.getKey(alias, pwd.toCharArray());
    return caprk;
  }


  /**
   * post表单数据
   *
   * @return
   */
  private Map<String, String> buildPostParam(BlueInvoice bin) {
	Map<String,String> paramsMap = new HashMap<String,String>();
    paramsMap.put("requestdatas", this.buildRequestDatas(bin));
    if(null!=this.buildEmailConfigs(bin)) {
     paramsMap.put("email", this.buildEmailConfigs(bin));
    }
    if(null!=this.buildSmsConfigs(bin)) {
     paramsMap.put("sms", this.buildSmsConfigs(bin));
    }
    if(null!=this.buildUrlConfigs(bin)) {
     paramsMap.put("url", this.buildUrlConfigs(bin));
    }
    //true:自动审核，即不需要人工在发票平台确认开票，直接进行开票 false:不自动审核，即需要人工确认
    //如果不传，代表true
    paramsMap.put("autoAudit", "true");
    return paramsMap;
  }


  /**
   * url回掉配置
   *
   * @return
   */
  private String buildUrlConfigs(BlueInvoice bin) {
	  //未填写回调URL
	if(null==bin.getBuildUrl() || StringUtils.isEmpty(bin.getBuildUrl())) {
		return null;
	}
	List<Object> datas = new ArrayList<Object>();
	Map<String,Object> data = new HashMap<String,Object>();	
    data.put("fpqqlsh", buildFpqqlsh(bin));
    data.put("url", bin.getBuildUrl());
    datas.add(data);
    GsonBuilder builder = new GsonBuilder();
    return builder.create().toJson(datas);
  }


  /**
   * 构造短信发送信息
   *
   * @return
   */
  private String buildSmsConfigs(BlueInvoice bin) {
	//未填写电话号码
	if(null==bin.getTel() ||StringUtils.isEmpty(bin.getTel())) {
		return null;
	}
	List<Object> datas = new ArrayList<Object>();
	Map<String,Object> data = new HashMap<String,Object>();
    data.put("fpqqlsh", buildFpqqlsh(bin));
    data.put("address", bin.getTel());
    datas.add(data);
    GsonBuilder builder = new GsonBuilder();
    return builder.create().toJson(datas);
  }


  /**
   * 构造email发送信息
   * 
   * @return
   */
  private String buildEmailConfigs(BlueInvoice bin) {
	//未填写email
	if(null==bin.getE_mails() ||StringUtils.isEmpty(bin.getE_mails())) {
		return null;
	}
    List<Object> datas = new ArrayList<Object>();
    Map<String,Object> data = new HashMap<String,Object>();
    data.put("fpqqlsh", buildFpqqlsh(bin));
    data.put("address", bin.getE_mails());
    datas.add(data);
    GsonBuilder builder = new GsonBuilder();
    return builder.create().toJson(datas);
  }

  /**
   * 构造requestdatas
   * 
   * @return
   */
  private String buildRequestDatas(BlueInvoice bin) {
    List<Object> datas = new ArrayList<Object>();
    Map<String,Object> data = new HashMap<String,Object>(); 
    if(null!=bin.getFpqqlsh() && !bin.getFpqqlsh().isEmpty()) {
    data.put("FPQQLSH",bin.getFpqqlsh());
    }
    if(null!=bin.getBz() && !bin.getBz().isEmpty()) {
    data.put("BZ", bin.getBz());	
    }
    if(null!=bin.getXsf_nsrsbh() && !bin.getXsf_nsrsbh().isEmpty()) {
    data.put("XSF_NSRSBH",bin.getXsf_nsrsbh());
    }
    if(null!=bin.getGmf_mc() && !bin.getGmf_mc().isEmpty()) {
    data.put("GMF_MC", bin.getGmf_mc());	
    } 
    if(null!=bin.getJshj()) {  
    data.put("JSHJ",bin.getJshj());
    }
    if(null!=bin.getOrgcode() && !bin.getOrgcode().isEmpty()) {
    data.put("ORGCODE", bin.getOrgcode());	
    }    
    if(null!=bin.getFphm() && !bin.getFphm().isEmpty()) {
    data.put("fpHm", bin.getFphm());
    } 
    if(null!=bin.getFpdm() && !bin.getFpdm().isEmpty()) {
        data.put("fpDm", bin.getFpdm());
        } 
    if(null!=bin.getKpr() && !bin.getKpr().isEmpty()) {
    data.put("KPR", bin.getKpr());
    } 
    if(null!=bin.getSkr() && !bin.getSkr().isEmpty()) {
        data.put("SKR", bin.getSkr());
    }
    if(null!=bin.getGmf_nsrsbh() && !bin.getGmf_nsrsbh().isEmpty()) {
        data.put("GMF_NSRSBH", bin.getGmf_nsrsbh());
    } 
    if(null!=bin.getGmf_dzdh() && !bin.getGmf_dzdh().isEmpty()) {
        data.put("GMF_DZDH", bin.getGmf_dzdh());
    } 
    if(null!=bin.getGmf_yhzh() && !bin.getGmf_yhzh().isEmpty()) {
        data.put("GMF_YHZH", bin.getGmf_yhzh());
    } 
    if(null!=bin.getDetails() &&bin.getDetails().size()>0) {
    data.put("items", buildItems(bin.getDetails()));
    } 
    datas.add(data);
    GsonBuilder builder = new GsonBuilder();
    return builder.create().toJson(datas);
  }


  /**
   * 构造request发票明细
   * 
   * @return
   */
  private List<Object> buildItems(List<BlueInvoiceDetailed> details) {
    List<Object> items = new ArrayList<Object>();
    for(BlueInvoiceDetailed de:details) {
    Map<String,Object> data = new HashMap<String,Object>();
    data.put("XMMC", de.getXmmc());
    data.put("XMSL", de.getXmsl());
    data.put("XMJSHJ",de.getXmjshj());
    data.put("SL",de.getSl());
    data.put("SPBM", de.getSpbm());
    items.add(data);
    }
    return items;
  }
}